{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "MhoQ0WE77laV"
   },
   "source": [
    "##### Copyright 2020 The TensorFlow Authors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "cellView": "form",
    "id": "_ckMIh7O7s6D",
    "tags": []
   },
   "outputs": [],
   "source": [
    "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "jYysdyb-CaWM"
   },
   "source": [
    "# Train and serve a TensorFlow model with TensorFlow Serving"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "E6FwTNtl3S4v"
   },
   "source": [
    "**Warning: This notebook is designed to be run in a Google Colab only**.  It installs packages on the system and requires root access.  If you want to run it in a local Jupyter notebook, please proceed with caution.\n",
    "\n",
    "Note: You can run this example right now in a Jupyter-style notebook, no setup required!  Just click \"Run in Google Colab\"\n",
    "\n",
    "<div class=\"devsite-table-wrapper\"><table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "<tr><td><a target=\"_blank\" href=\"https://www.tensorflow.org/tfx/tutorials/serving/rest_simple\">\n",
    "<img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />View on TensorFlow.org</a></td>\n",
    "<td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/tfx/blob/master/docs/tutorials/serving/rest_simple.ipynb\">\n",
    "<img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Run in Google Colab</a></td>\n",
    "<td><a target=\"_blank\" href=\"https://github.com/tensorflow/tfx/blob/master/docs/tutorials/serving/rest_simple.ipynb\">\n",
    "<img width=32px src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">View source on GitHub</a></td>\n",
    "<td><a href=\"https://storage.googleapis.com/tensorflow_docs/tfx/docs/tutorials/serving/rest_simple.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Download notebook</a></td>\n",
    "</tr></table></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "FbVhjPpzn6BM"
   },
   "source": [
    "This guide trains a neural network model to classify [images of clothing, like sneakers and shirts](https://github.com/zalandoresearch/fashion-mnist), saves the trained model, and then serves it with [TensorFlow Serving](https://www.tensorflow.org/tfx/guide/serving).  The focus is on TensorFlow Serving, rather than the modeling and training in TensorFlow, so for a complete example which focuses on the modeling and training see the [Basic Classification example](https://github.com/tensorflow/docs/blob/master/site/en/r1/tutorials/keras/basic_classification.ipynb).\n",
    "\n",
    "This guide uses [tf.keras](https://github.com/tensorflow/docs/blob/master/site/en/r1/guide/keras.ipynb), a high-level API to build and train models in TensorFlow."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://mirrors.tencent.com/pypi/simple/, https://mirrors.tencent.com/repository/pypi/tencent_pypi/simple\n",
      "Requirement already satisfied: tensorflow in /usr/local/lib/python3.8/dist-packages (2.3.0)\n",
      "Requirement already satisfied: requests in /usr/local/lib/python3.8/dist-packages (2.27.1)\n",
      "Collecting matplotlib\n",
      "  Downloading https://mirrors.tencent.com/pypi/packages/42/18/50a124008e624830fb8e2a5384802ba99ee0443994ebdee8f548c3732039/matplotlib-3.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl (11.3 MB)\n",
      "     |████████████████████████████████| 11.3 MB 4.7 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: wrapt>=1.11.1 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.13.3)\n",
      "Requirement already satisfied: astunparse==1.6.3 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.6.3)\n",
      "Requirement already satisfied: numpy<1.19.0,>=1.16.0 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.18.5)\n",
      "Requirement already satisfied: wheel>=0.26 in /usr/lib/python3/dist-packages (from tensorflow) (0.30.0)\n",
      "Requirement already satisfied: tensorboard<3,>=2.3.0 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (2.9.1)\n",
      "Requirement already satisfied: h5py<2.11.0,>=2.10.0 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (2.10.0)\n",
      "Requirement already satisfied: scipy==1.4.1 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.4.1)\n",
      "Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (3.3.0)\n",
      "Requirement already satisfied: absl-py>=0.7.0 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.2.0)\n",
      "Requirement already satisfied: google-pasta>=0.1.8 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (0.2.0)\n",
      "Requirement already satisfied: tensorflow-estimator<2.4.0,>=2.3.0 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (2.3.0)\n",
      "Requirement already satisfied: grpcio>=1.8.6 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.26.0)\n",
      "Requirement already satisfied: keras-preprocessing<1.2,>=1.1.1 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.1.2)\n",
      "Requirement already satisfied: gast==0.3.3 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (0.3.3)\n",
      "Requirement already satisfied: protobuf>=3.9.2 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (3.19.3)\n",
      "Requirement already satisfied: six>=1.12.0 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.16.0)\n",
      "Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.8/dist-packages (from tensorflow) (1.1.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.8/dist-packages (from requests) (2021.10.8)\n",
      "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.8/dist-packages (from requests) (1.26.5)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.8/dist-packages (from requests) (3.3)\n",
      "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.8/dist-packages (from requests) (2.0.10)\n",
      "Requirement already satisfied: pyparsing>=2.2.1 in /usr/local/lib/python3.8/dist-packages (from matplotlib) (3.0.6)\n",
      "Collecting kiwisolver>=1.0.1\n",
      "  Downloading https://mirrors.tencent.com/pypi/packages/86/7a/6b438da7534dacd232ed4e19f74f4edced2cda9494d7e6536f54edfdf4a5/kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl (1.2 MB)\n",
      "     |████████████████████████████████| 1.2 MB 480 kB/s            \n",
      "\u001b[?25hCollecting pillow>=6.2.0\n",
      "  Downloading https://mirrors.tencent.com/pypi/packages/20/cb/261342854f01ff18281e97ec8e6a7ce3beaf8e1091d1cebd52776049358d/Pillow-9.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.1 MB)\n",
      "     |████████████████████████████████| 3.1 MB 1.6 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.8/dist-packages (from matplotlib) (21.3)\n",
      "Collecting cycler>=0.10\n",
      "  Downloading https://mirrors.tencent.com/pypi/packages/5c/f9/695d6bedebd747e5eb0fe8fad57b72fdf25411273a39791cde838d5a8f51/cycler-0.11.0-py3-none-any.whl (6.4 kB)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.8/dist-packages (from matplotlib) (2.8.2)\n",
      "Collecting fonttools>=4.22.0\n",
      "  Downloading https://mirrors.tencent.com/pypi/packages/ad/27/094dd5d09d3a57f7a5f27414ae5c1405bae1164922f1bb61fd8a748e8f65/fonttools-4.34.4-py3-none-any.whl (944 kB)\n",
      "     |████████████████████████████████| 944 kB 5.7 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: werkzeug>=1.0.1 in /usr/local/lib/python3.8/dist-packages (from tensorboard<3,>=2.3.0->tensorflow) (2.0.2)\n",
      "Requirement already satisfied: setuptools>=41.0.0 in /usr/local/lib/python3.8/dist-packages (from tensorboard<3,>=2.3.0->tensorflow) (60.5.0)\n",
      "Requirement already satisfied: tensorboard-data-server<0.7.0,>=0.6.0 in /usr/local/lib/python3.8/dist-packages (from tensorboard<3,>=2.3.0->tensorflow) (0.6.1)\n",
      "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.8/dist-packages (from tensorboard<3,>=2.3.0->tensorflow) (3.4.1)\n",
      "Requirement already satisfied: tensorboard-plugin-wit>=1.6.0 in /usr/local/lib/python3.8/dist-packages (from tensorboard<3,>=2.3.0->tensorflow) (1.8.1)\n",
      "Requirement already satisfied: google-auth<3,>=1.6.3 in /usr/local/lib/python3.8/dist-packages (from tensorboard<3,>=2.3.0->tensorflow) (2.3.3)\n",
      "Requirement already satisfied: google-auth-oauthlib<0.5,>=0.4.1 in /usr/local/lib/python3.8/dist-packages (from tensorboard<3,>=2.3.0->tensorflow) (0.4.6)\n",
      "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.8/dist-packages (from google-auth<3,>=1.6.3->tensorboard<3,>=2.3.0->tensorflow) (0.2.8)\n",
      "Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.8/dist-packages (from google-auth<3,>=1.6.3->tensorboard<3,>=2.3.0->tensorflow) (4.7.2)\n",
      "Requirement already satisfied: cachetools<5.0,>=2.0.0 in /usr/local/lib/python3.8/dist-packages (from google-auth<3,>=1.6.3->tensorboard<3,>=2.3.0->tensorflow) (4.2.4)\n",
      "Requirement already satisfied: requests-oauthlib>=0.7.0 in /usr/local/lib/python3.8/dist-packages (from google-auth-oauthlib<0.5,>=0.4.1->tensorboard<3,>=2.3.0->tensorflow) (1.3.0)\n",
      "Requirement already satisfied: importlib-metadata>=4.4 in /usr/local/lib/python3.8/dist-packages (from markdown>=2.6.8->tensorboard<3,>=2.3.0->tensorflow) (4.12.0)\n",
      "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.8/dist-packages (from importlib-metadata>=4.4->markdown>=2.6.8->tensorboard<3,>=2.3.0->tensorflow) (3.8.1)\n",
      "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in /usr/local/lib/python3.8/dist-packages (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard<3,>=2.3.0->tensorflow) (0.4.8)\n",
      "Requirement already satisfied: oauthlib>=3.0.0 in /usr/local/lib/python3.8/dist-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<0.5,>=0.4.1->tensorboard<3,>=2.3.0->tensorflow) (3.1.1)\n",
      "Installing collected packages: pillow, kiwisolver, fonttools, cycler, matplotlib\n",
      "Successfully installed cycler-0.11.0 fonttools-4.34.4 kiwisolver-1.4.4 matplotlib-3.5.2 pillow-9.2.0\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\n",
      "\u001b[33mWARNING: You are using pip version 21.3.1; however, version 22.2 is available.\n",
      "You should consider upgrading via the '/usr/bin/python -m pip install --upgrade pip' command.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "# 安装基础环境\n",
    "!pip install tensorflow requests matplotlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "id": "FWkuJabJSKGB",
    "tags": []
   },
   "outputs": [],
   "source": [
    "import sys\n",
    "\n",
    "# Confirm that we're using Python 3\n",
    "assert sys.version_info.major == 3, 'Oops, not running Python 3. Use Runtime > Change runtime type'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "id": "dzLKpmZICaWN",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Installing dependencies for Colab environment\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\n",
      "\u001b[33mWARNING: You are using pip version 21.3.1; however, version 22.2 is available.\n",
      "You should consider upgrading via the '/usr/bin/python -m pip install --upgrade pip' command.\u001b[0m\n",
      "TensorFlow version: 2.3.0\n"
     ]
    }
   ],
   "source": [
    "# TensorFlow and tf.keras\n",
    "print(\"Installing dependencies for Colab environment\")\n",
    "!pip install -Uq grpcio==1.26.0\n",
    "\n",
    "import tensorflow as tf\n",
    "from tensorflow import keras\n",
    "\n",
    "# Helper libraries\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import os\n",
    "import subprocess\n",
    "\n",
    "print('TensorFlow version: {}'.format(tf.__version__))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5jAk1ZXqTJqN"
   },
   "source": [
    "## Create your model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "yR0EdgrLCaWR"
   },
   "source": [
    "### Import the Fashion MNIST dataset\n",
    "\n",
    "This guide uses the [Fashion MNIST](https://github.com/zalandoresearch/fashion-mnist) dataset which contains 70,000 grayscale images in 10 categories. The images show individual articles of clothing at low resolution (28 by 28 pixels), as seen here:\n",
    "\n",
    "<table>\n",
    "  <tr><td>\n",
    "    <img src=\"https://tensorflow.org/images/fashion-mnist-sprite.png\"\n",
    "         alt=\"Fashion MNIST sprite\"  width=\"600\">\n",
    "  </td></tr>\n",
    "  <tr><td align=\"center\">\n",
    "    <b>Figure 1.</b> <a href=\"https://github.com/zalandoresearch/fashion-mnist\">Fashion-MNIST samples</a> (by Zalando, MIT License).<br/>&nbsp;\n",
    "  </td></tr>\n",
    "</table>\n",
    "\n",
    "Fashion MNIST is intended as a drop-in replacement for the classic [MNIST](http://yann.lecun.com/exdb/mnist/) dataset—often used as the \"Hello, World\" of machine learning programs for computer vision. You can access the Fashion MNIST directly from TensorFlow, just import and load the data.\n",
    "\n",
    "Note: Although these are really images, they are loaded as NumPy arrays and not binary image objects."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "id": "7MqDQO0KCaWS",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz\n",
      "26427392/26421880 [==============================] - 1s 0us/step\n",
      "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz\n",
      "8192/5148 [===============================================] - 0s 0us/step\n",
      "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz\n",
      "4423680/4422102 [==============================] - 0s 0us/step\n",
      "\n",
      "train_images.shape: (60000, 28, 28, 1), of float64\n",
      "test_images.shape: (10000, 28, 28, 1), of float64\n"
     ]
    }
   ],
   "source": [
    "fashion_mnist = keras.datasets.fashion_mnist\n",
    "(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()\n",
    "\n",
    "# wget https://storage.googleapis.com/cvdf-datasets/mnist/train-images-idx3-ubyte.gz\n",
    "# wget https://storage.googleapis.com/cvdf-datasets/mnist/train-labels-idx1-ubyte.gz\n",
    "# wget https://storage.googleapis.com/cvdf-datasets/mnist/t10k-images-idx3-ubyte.gz\n",
    "# wget https://storage.googleapis.com/cvdf-datasets/mnist/t10k-labels-idx1-ubyte.gz\n",
    "\n",
    "# scale the values to 0.0 to 1.0\n",
    "train_images = train_images / 255.0\n",
    "test_images = test_images / 255.0\n",
    "\n",
    "# reshape for feeding into the model\n",
    "train_images = train_images.reshape(train_images.shape[0], 28, 28, 1)\n",
    "test_images = test_images.reshape(test_images.shape[0], 28, 28, 1)\n",
    "\n",
    "class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',\n",
    "               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']\n",
    "\n",
    "print('\\ntrain_images.shape: {}, of {}'.format(train_images.shape, train_images.dtype))\n",
    "print('test_images.shape: {}, of {}'.format(test_images.shape, test_images.dtype))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "PDu7OX8Nf5PY"
   },
   "source": [
    "### Train and evaluate your model\n",
    "\n",
    "Let's use the simplest possible CNN, since we're not focused on the modeling part."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "LTNN0ANGgA36",
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2022-07-28 17:26:27.097399: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory\n",
      "2022-07-28 17:26:27.097448: W tensorflow/stream_executor/cuda/cuda_driver.cc:312] failed call to cuInit: UNKNOWN ERROR (303)\n",
      "2022-07-28 17:26:27.097470: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (pengluan-60e0): /proc/driver/nvidia/version does not exist\n",
      "2022-07-28 17:26:27.097948: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN)to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA\n",
      "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n",
      "2022-07-28 17:26:27.108732: I tensorflow/core/platform/profile_utils/cpu_utils.cc:104] CPU Frequency: 2394370000 Hz\n",
      "2022-07-28 17:26:27.111923: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x2c123a0 initialized for platform Host (this does not guarantee that XLA will be used). Devices:\n",
      "2022-07-28 17:26:27.111952: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "Conv1 (Conv2D)               (None, 13, 13, 8)         80        \n",
      "_________________________________________________________________\n",
      "flatten (Flatten)            (None, 1352)              0         \n",
      "_________________________________________________________________\n",
      "Dense (Dense)                (None, 10)                13530     \n",
      "=================================================================\n",
      "Total params: 13,610\n",
      "Trainable params: 13,610\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n",
      "Epoch 1/5\n",
      "1875/1875 [==============================] - 4s 2ms/step - loss: 0.5358 - sparse_categorical_accuracy: 0.8152\n",
      "Epoch 2/5\n",
      "1875/1875 [==============================] - 4s 2ms/step - loss: 0.3867 - sparse_categorical_accuracy: 0.8626\n",
      "Epoch 3/5\n",
      "1875/1875 [==============================] - 4s 2ms/step - loss: 0.3474 - sparse_categorical_accuracy: 0.8772\n",
      "Epoch 4/5\n",
      "1875/1875 [==============================] - 4s 2ms/step - loss: 0.3254 - sparse_categorical_accuracy: 0.8840\n",
      "Epoch 5/5\n",
      "1875/1875 [==============================] - 4s 2ms/step - loss: 0.3117 - sparse_categorical_accuracy: 0.8885\n",
      "313/313 [==============================] - 0s 1ms/step - loss: 0.3455 - sparse_categorical_accuracy: 0.8774\n",
      "\n",
      "Test accuracy: 0.8773999810218811\n"
     ]
    }
   ],
   "source": [
    "model = keras.Sequential([\n",
    "  keras.layers.Conv2D(input_shape=(28,28,1), filters=8, kernel_size=3, \n",
    "                      strides=2, activation='relu', name='Conv1'),\n",
    "  keras.layers.Flatten(),\n",
    "  keras.layers.Dense(10, name='Dense')\n",
    "])\n",
    "model.summary()\n",
    "\n",
    "testing = False\n",
    "epochs = 5\n",
    "\n",
    "model.compile(optimizer='adam', \n",
    "              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
    "              metrics=[keras.metrics.SparseCategoricalAccuracy()])\n",
    "model.fit(train_images, train_labels, epochs=epochs)\n",
    "\n",
    "test_loss, test_acc = model.evaluate(test_images, test_labels)\n",
    "print('\\nTest accuracy: {}'.format(test_acc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "AwGPItyphqXT"
   },
   "source": [
    "## Save your model\n",
    "\n",
    "To load our trained model into TensorFlow Serving we first need to save it in [SavedModel](https://www.tensorflow.org/versions/r1.15/api_docs/python/tf/saved_model) format.  This will create a protobuf file in a well-defined directory hierarchy, and will include a version number.  [TensorFlow Serving](https://www.tensorflow.org/tfx/guide/serving) allows us to select which version of a model, or \"servable\" we want to use when we make inference requests.  Each version will be exported to a different sub-directory under the given path."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "id": "0w5Rq8SsgWE6",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "export_path = export_dir/1\n",
      "\n",
      "INFO:tensorflow:Assets written to: export_dir/1/assets\n",
      "\n",
      "Saved model:\n",
      "total 74\n",
      "drwxr-xr-x 2 root root      0 7月  28 17:37 assets\n",
      "-rw-r--r-- 1 root root  74006 7月  28 17:37 saved_model.pb\n",
      "drwxr-xr-x 2 root root 168637 7月  28 17:37 variables\n"
     ]
    }
   ],
   "source": [
    "# Fetch the Keras session and save the model\n",
    "# The signature definition is defined by the input and output tensors,\n",
    "# and stored with the default serving key\n",
    "import tempfile\n",
    "import shutil\n",
    "\n",
    "# MODEL_DIR = tempfile.gettempdir()\n",
    "MODEL_DIR = 'export_dir'\n",
    "version = 1\n",
    "export_path = os.path.join(MODEL_DIR, str(version))\n",
    "print('export_path = {}\\n'.format(export_path))\n",
    "shutil.rmtree(export_path,ignore_errors=True)\n",
    "tf.keras.models.save_model(\n",
    "    model,\n",
    "    export_path,\n",
    "    overwrite=True,\n",
    "    include_optimizer=True,\n",
    "    save_format=None,\n",
    "    signatures=None,\n",
    "    options=None\n",
    ")\n",
    "\n",
    "print('\\nSaved model:')\n",
    "!ls -l {export_path}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "FM7B_RuDYoIj"
   },
   "source": [
    "## Examine your saved model\n",
    "\n",
    "We'll use the command line utility `saved_model_cli` to look at the [MetaGraphDefs](https://www.tensorflow.org/versions/r1.15/api_docs/python/tf/MetaGraphDef) (the models) and [SignatureDefs](../signature_defs) (the methods you can call) in our SavedModel.  See [this discussion of the SavedModel CLI](https://github.com/tensorflow/docs/blob/master/site/en/r1/guide/saved_model.md#cli-to-inspect-and-execute-savedmodel) in the TensorFlow Guide."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "id": "LU4GDF_aYtfQ",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2022-07-28 17:37:31.624747: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'libcudart.so.10.1'; dlerror: libcudart.so.10.1: cannot open shared object file: No such file or directory\n",
      "2022-07-28 17:37:31.624789: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n",
      "\n",
      "MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:\n",
      "\n",
      "signature_def['__saved_model_init_op']:\n",
      "  The given SavedModel SignatureDef contains the following input(s):\n",
      "  The given SavedModel SignatureDef contains the following output(s):\n",
      "    outputs['__saved_model_init_op'] tensor_info:\n",
      "        dtype: DT_INVALID\n",
      "        shape: unknown_rank\n",
      "        name: NoOp\n",
      "  Method name is: \n",
      "\n",
      "signature_def['serving_default']:\n",
      "  The given SavedModel SignatureDef contains the following input(s):\n",
      "    inputs['Conv1_input'] tensor_info:\n",
      "        dtype: DT_FLOAT\n",
      "        shape: (-1, 28, 28, 1)\n",
      "        name: serving_default_Conv1_input:0\n",
      "  The given SavedModel SignatureDef contains the following output(s):\n",
      "    outputs['Dense'] tensor_info:\n",
      "        dtype: DT_FLOAT\n",
      "        shape: (-1, 10)\n",
      "        name: StatefulPartitionedCall:0\n",
      "  Method name is: tensorflow/serving/predict\n",
      "\n",
      "Defined Functions:\n",
      "  Function Name: '__call__'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #2\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          Conv1_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='Conv1_input')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #3\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          Conv1_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='Conv1_input')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #4\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "\n",
      "  Function Name: '_default_save_signature'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          Conv1_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='Conv1_input')\n",
      "\n",
      "  Function Name: 'call_and_return_all_conditional_losses'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #2\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          Conv1_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='Conv1_input')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #3\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          Conv1_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='Conv1_input')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #4\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n"
     ]
    }
   ],
   "source": [
    "!saved_model_cli show --dir {export_path} --all"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "lSPWuegUb7Eo"
   },
   "source": [
    "That tells us a lot about our model!  In this case we just trained our model, so we already know the inputs and outputs, but if we didn't this would be important information.  It doesn't tell us everything, like the fact that this is grayscale image data for example, but it's a great start."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "DBgsyhytS6KD"
   },
   "source": [
    "## Serve your model with TensorFlow Serving\n",
    "\n",
    "**Warning: If you are running this NOT on a Google Colab,** following cells\n",
    "will install packages on the system with root access. If you want to run it in\n",
    "a local Jupyter notebook, please proceed with caution.\n",
    "\n",
    "### Add TensorFlow Serving distribution URI as a package source:\n",
    "\n",
    "We're preparing to install TensorFlow Serving using [Aptitude](https://wiki.debian.org/Aptitude) since this Colab runs in a Debian environment.  We'll add the `tensorflow-model-server` package to the list of packages that Aptitude knows about.  Note that we're running as root.\n",
    "\n",
    "Note: This example is running TensorFlow Serving natively, but [you can also run it in a Docker container](https://www.tensorflow.org/tfx/serving/docker), which is one of the easiest ways to get started using TensorFlow Serving."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "id": "v2hF_ChoOrEd",
    "tags": []
   },
   "outputs": [],
   "source": [
    "import sys\n",
    "# We need sudo prefix if not on a Google Colab.\n",
    "if 'google.colab' not in sys.modules:\n",
    "  SUDO_IF_NEEDED = 'sudo'\n",
    "else:\n",
    "  SUDO_IF_NEEDED = ''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "id": "EWg9X2QHlbGS",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "deb http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal\n",
      "  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n",
      "                                 Dload  Upload   Total   Spent    Left  Speed\n",
      "100  2943  100  2943    0     0   6860      0 --:--:-- --:--:-- --:--:--  6860\n",
      "OK\n",
      "Hit:1 http://storage.googleapis.com/tensorflow-serving-apt stable InRelease\n",
      "Ign:2 https://mirrors.tencent.com/debian stretch InRelease                     \u001b[0m\u001b[33m\u001b[33m\n",
      "Get:3 https://mirrors.tencent.com/debian stretch-updates InRelease [93.6 kB]   \u001b[0m\n",
      "Err:3 https://mirrors.tencent.com/debian stretch-updates InRelease             \u001b[0m\u001b[33m\n",
      "  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 04EE7237B7D453EC NO_PUBKEY 648ACFD622F3D138\n",
      "Get:4 https://mirrors.tencent.com/debian stretch Release [118 kB]              \u001b[0m\n",
      "Get:5 https://mirrors.tencent.com/debian stretch Release.gpg [3,177 B]     \u001b[0m\u001b[0m\u001b[33m\n",
      "Hit:6 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease     \u001b[0m \u001b[0m\u001b[33m\n",
      "Ign:5 https://mirrors.tencent.com/debian stretch Release.gpg              \n",
      "Hit:7 https://deb.nodesource.com/node_16.x bionic InRelease\n",
      "Reading package lists... Done\u001b[0m                  \u001b[33m\u001b[33m\n",
      "W: GPG error: https://mirrors.tencent.com/debian stretch-updates InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 04EE7237B7D453EC NO_PUBKEY 648ACFD622F3D138\n",
      "E: The repository 'https://mirrors.tencent.com/debian stretch-updates InRelease' is not signed.\n",
      "N: Updating from such a repository can't be done securely, and is therefore disabled by default.\n",
      "N: See apt-secure(8) manpage for repository creation and user configuration details.\n",
      "W: GPG error: https://mirrors.tencent.com/debian stretch Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 04EE7237B7D453EC NO_PUBKEY 648ACFD622F3D138 NO_PUBKEY 0E98404D386FA1D9 NO_PUBKEY EF0F382A1A7B6500\n",
      "E: The repository 'https://mirrors.tencent.com/debian stretch Release' is not signed.\n",
      "N: Updating from such a repository can't be done securely, and is therefore disabled by default.\n",
      "N: See apt-secure(8) manpage for repository creation and user configuration details.\n"
     ]
    }
   ],
   "source": [
    "# This is the same as you would do from your command line, but without the [arch=amd64], and no sudo\n",
    "# You would instead do:\n",
    "# echo \"deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal\" | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list && \\\n",
    "# curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | sudo apt-key add -\n",
    "\n",
    "!echo \"deb http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal\" | tee /etc/apt/sources.list.d/tensorflow-serving.list && \\\n",
    "curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | apt-key add -\n",
    "! apt update"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "W1ZVp_VOU7Wu"
   },
   "source": [
    "### Install TensorFlow Serving\n",
    "\n",
    "This is all you need - one command line!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "id": "ygwa9AgRloYy",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Reading package lists... Done\n",
      "Building dependency tree       \n",
      "Reading state information... Done\n",
      "tensorflow-model-server is already the newest version (2.9.1).\n",
      "0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.\n"
     ]
    }
   ],
   "source": [
    "! apt-get install tensorflow-model-server"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "k5NrYdQeVm52"
   },
   "source": [
    "### Start running TensorFlow Serving\n",
    "\n",
    "This is where we start running TensorFlow Serving and load our model.  After it loads we can start making inference requests using REST.  There are some important parameters:\n",
    "\n",
    "* `rest_api_port`: The port that you'll use for REST requests.\n",
    "* `model_name`: You'll use this in the URL of REST requests.  It can be anything.\n",
    "* `model_base_path`: This is the path to the directory where you've saved your model.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "id": "aUgp3vUdU5GS",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "export_dir\n"
     ]
    }
   ],
   "source": [
    "os.environ[\"MODEL_DIR\"] = MODEL_DIR\n",
    "print(MODEL_DIR)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hit:1 http://storage.googleapis.com/tensorflow-serving-apt stable InRelease\n",
      "Ign:2 https://mirrors.tencent.com/debian stretch InRelease                     \u001b[0m\u001b[33m\u001b[33m\n",
      "Get:3 https://mirrors.tencent.com/debian stretch-updates InRelease [93.6 kB]   \u001b[0m\n",
      "Err:3 https://mirrors.tencent.com/debian stretch-updates InRelease             \u001b[0m\u001b[33m\n",
      "  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 04EE7237B7D453EC NO_PUBKEY 648ACFD622F3D138\n",
      "Get:4 https://mirrors.tencent.com/debian stretch Release [118 kB]              \u001b[0m\n",
      "Hit:5 https://deb.nodesource.com/node_16.x bionic InRelease                \u001b[0m\u001b[0m\u001b[33m\n",
      "Get:6 https://mirrors.tencent.com/debian stretch Release.gpg [3,177 B]         \u001b[0mm\n",
      "Ign:6 https://mirrors.tencent.com/debian stretch Release.gpg                   \u001b[0m\u001b[33m\n",
      "Hit:7 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease          \u001b[33m\n",
      "Reading package lists... Done\u001b[0m\u001b[33m\n",
      "W: GPG error: https://mirrors.tencent.com/debian stretch-updates InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 04EE7237B7D453EC NO_PUBKEY 648ACFD622F3D138\n",
      "E: The repository 'https://mirrors.tencent.com/debian stretch-updates InRelease' is not signed.\n",
      "N: Updating from such a repository can't be done securely, and is therefore disabled by default.\n",
      "N: See apt-secure(8) manpage for repository creation and user configuration details.\n",
      "W: GPG error: https://mirrors.tencent.com/debian stretch Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 04EE7237B7D453EC NO_PUBKEY 648ACFD622F3D138 NO_PUBKEY 0E98404D386FA1D9 NO_PUBKEY EF0F382A1A7B6500\n",
      "E: The repository 'https://mirrors.tencent.com/debian stretch Release' is not signed.\n",
      "N: Updating from such a repository can't be done securely, and is therefore disabled by default.\n",
      "N: See apt-secure(8) manpage for repository creation and user configuration details.\n",
      "Reading package lists... Done\n",
      "Building dependency tree       \n",
      "Reading state information... Done\n",
      "E: Unable to locate package libgtk-3-dev\n",
      "E: Unable to locate package libfreetype6-dev\n",
      "E: Unable to locate package libx11-dev\n",
      "E: Unable to locate package libxinerama-dev\n",
      "E: Unable to locate package libxrandr-dev\n",
      "E: Unable to locate package libxcursor-dev\n",
      "E: Unable to locate package mesa-common-dev\n",
      "E: Unable to locate package libasound2-dev\n",
      "E: Unable to locate package freeglut3-dev\n",
      "E: Unable to locate package libxcomposite-dev\n",
      "E: Unable to locate package libcurl4-openssl-dev\n"
     ]
    }
   ],
   "source": [
    "! apt update\n",
    "! apt-get install -y g++ libgtk-3-dev libfreetype6-dev libx11-dev libxinerama-dev libxrandr-dev libxcursor-dev mesa-common-dev libasound2-dev freeglut3-dev libxcomposite-dev libcurl4-openssl-dev\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "id": "kJDhHNJVnaLN",
    "tags": []
   },
   "outputs": [],
   "source": [
    "%%bash --bg \n",
    "nohup tensorflow_model_server \\\n",
    "  --rest_api_port=8501 \\\n",
    "  --model_name=fashion_model \\\n",
    "  --model_base_path=\"${MODEL_DIR}\" >server.log 2>&1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "id": "IxbeiOCUUs2z",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensorflow_model_server: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by tensorflow_model_server)\n",
      "tensorflow_model_server: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by tensorflow_model_server)\n",
      "tensorflow_model_server: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by tensorflow_model_server)\n"
     ]
    }
   ],
   "source": [
    "!tail server.log"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vwg1JKaGXWAg"
   },
   "source": [
    "## Make a request to your model in TensorFlow Serving\n",
    "\n",
    "First, let's take a look at a random example from our test data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "id": "Luqm_Jyff9iR",
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def show(idx, title):\n",
    "  plt.figure()\n",
    "  plt.imshow(test_images[idx].reshape(28,28))\n",
    "  plt.axis('off')\n",
    "  plt.title('\\n\\n{}'.format(title), fontdict={'size': 16})\n",
    "\n",
    "import random\n",
    "rando = random.randint(0,len(test_images)-1)\n",
    "show(rando, 'An Example Image: {}'.format(class_names[test_labels[rando]]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "TKnEHeTrbh3L"
   },
   "source": [
    "Ok, that looks interesting.  How hard is that for you to recognize? Now let's create the JSON object for a batch of  three inference requests, and see how well our model recognizes things:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "id": "2dsD7KQG1m-R",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Data: {\"signature_name\": \"serving_default\", \"instances\": ...  [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0]]]]}\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "data = json.dumps({\"signature_name\": \"serving_default\", \"instances\": test_images[0:3].tolist()})\n",
    "print('Data: {} ... {}'.format(data[:50], data[len(data)-52:]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ReQd4QESIwXN"
   },
   "source": [
    "### Make REST requests"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "iT3J-lHrhOYQ"
   },
   "source": [
    "#### Newest version of the servable\n",
    "\n",
    "We'll send a predict request as a POST to our server's REST endpoint, and pass it three examples.  We'll ask our server to give us the latest version of our servable by not specifying a particular version."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "id": "vGvFyuIzW6n6"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\n",
      "\u001b[33mWARNING: You are using pip version 21.3.1; however, version 22.2 is available.\n",
      "You should consider upgrading via the '/usr/bin/python -m pip install --upgrade pip' command.\u001b[0m\n"
     ]
    },
    {
     "ename": "ConnectionError",
     "evalue": "HTTPConnectionPool(host='localhost', port=8501): Max retries exceeded with url: /v1/models/fashion_model:predict (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f1a8f306130>: Failed to establish a new connection: [Errno 111] Connection refused'))",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mConnectionRefusedError\u001b[0m                    Traceback (most recent call last)",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/connection.py:169\u001b[0m, in \u001b[0;36mHTTPConnection._new_conn\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    168\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 169\u001b[0m     conn \u001b[38;5;241m=\u001b[39m \u001b[43mconnection\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_connection\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    170\u001b[0m \u001b[43m        \u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_dns_host\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mport\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mextra_kw\u001b[49m\n\u001b[1;32m    171\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    173\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m SocketTimeout:\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/util/connection.py:96\u001b[0m, in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[1;32m     95\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m err \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 96\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m err\n\u001b[1;32m     98\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m socket\u001b[38;5;241m.\u001b[39merror(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mgetaddrinfo returns an empty list\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/util/connection.py:86\u001b[0m, in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[1;32m     85\u001b[0m     sock\u001b[38;5;241m.\u001b[39mbind(source_address)\n\u001b[0;32m---> 86\u001b[0m \u001b[43msock\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43msa\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     87\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m sock\n",
      "\u001b[0;31mConnectionRefusedError\u001b[0m: [Errno 111] Connection refused",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[0;31mNewConnectionError\u001b[0m                        Traceback (most recent call last)",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/connectionpool.py:699\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001b[0m\n\u001b[1;32m    698\u001b[0m \u001b[38;5;66;03m# Make the request on the httplib connection object.\u001b[39;00m\n\u001b[0;32m--> 699\u001b[0m httplib_response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_make_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    700\u001b[0m \u001b[43m    \u001b[49m\u001b[43mconn\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    701\u001b[0m \u001b[43m    \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    702\u001b[0m \u001b[43m    \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    703\u001b[0m \u001b[43m    \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout_obj\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    704\u001b[0m \u001b[43m    \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    705\u001b[0m \u001b[43m    \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    706\u001b[0m \u001b[43m    \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    707\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    709\u001b[0m \u001b[38;5;66;03m# If we're going to release the connection in ``finally:``, then\u001b[39;00m\n\u001b[1;32m    710\u001b[0m \u001b[38;5;66;03m# the response doesn't need to know about the connection. Otherwise\u001b[39;00m\n\u001b[1;32m    711\u001b[0m \u001b[38;5;66;03m# it will also try to release it and we'll have a double-release\u001b[39;00m\n\u001b[1;32m    712\u001b[0m \u001b[38;5;66;03m# mess.\u001b[39;00m\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/connectionpool.py:394\u001b[0m, in \u001b[0;36mHTTPConnectionPool._make_request\u001b[0;34m(self, conn, method, url, timeout, chunked, **httplib_request_kw)\u001b[0m\n\u001b[1;32m    393\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 394\u001b[0m         \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mhttplib_request_kw\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    396\u001b[0m \u001b[38;5;66;03m# We are swallowing BrokenPipeError (errno.EPIPE) since the server is\u001b[39;00m\n\u001b[1;32m    397\u001b[0m \u001b[38;5;66;03m# legitimately able to close the connection after sending a valid response.\u001b[39;00m\n\u001b[1;32m    398\u001b[0m \u001b[38;5;66;03m# With this behaviour, the received response is still readable.\u001b[39;00m\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/connection.py:234\u001b[0m, in \u001b[0;36mHTTPConnection.request\u001b[0;34m(self, method, url, body, headers)\u001b[0m\n\u001b[1;32m    233\u001b[0m     headers[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUser-Agent\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m _get_default_user_agent()\n\u001b[0;32m--> 234\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mHTTPConnection\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/usr/lib/python3.8/http/client.py:1256\u001b[0m, in \u001b[0;36mHTTPConnection.request\u001b[0;34m(self, method, url, body, headers, encode_chunked)\u001b[0m\n\u001b[1;32m   1255\u001b[0m \u001b[38;5;124;03m\"\"\"Send a complete request to the server.\"\"\"\u001b[39;00m\n\u001b[0;32m-> 1256\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_send_request\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/usr/lib/python3.8/http/client.py:1302\u001b[0m, in \u001b[0;36mHTTPConnection._send_request\u001b[0;34m(self, method, url, body, headers, encode_chunked)\u001b[0m\n\u001b[1;32m   1301\u001b[0m     body \u001b[38;5;241m=\u001b[39m _encode(body, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mbody\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m-> 1302\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mendheaders\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/usr/lib/python3.8/http/client.py:1251\u001b[0m, in \u001b[0;36mHTTPConnection.endheaders\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m   1250\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m CannotSendHeader()\n\u001b[0;32m-> 1251\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_send_output\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage_body\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/usr/lib/python3.8/http/client.py:1011\u001b[0m, in \u001b[0;36mHTTPConnection._send_output\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m   1010\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_buffer[:]\n\u001b[0;32m-> 1011\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmsg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   1013\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m message_body \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m   1014\u001b[0m \n\u001b[1;32m   1015\u001b[0m     \u001b[38;5;66;03m# create a consistent interface to message_body\u001b[39;00m\n",
      "File \u001b[0;32m/usr/lib/python3.8/http/client.py:951\u001b[0m, in \u001b[0;36mHTTPConnection.send\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m    950\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mauto_open:\n\u001b[0;32m--> 951\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    952\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/connection.py:200\u001b[0m, in \u001b[0;36mHTTPConnection.connect\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    199\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mconnect\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[0;32m--> 200\u001b[0m     conn \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_new_conn\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    201\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_prepare_conn(conn)\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/connection.py:181\u001b[0m, in \u001b[0;36mHTTPConnection._new_conn\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    180\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m SocketError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m--> 181\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m NewConnectionError(\n\u001b[1;32m    182\u001b[0m         \u001b[38;5;28mself\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFailed to establish a new connection: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m%\u001b[39m e\n\u001b[1;32m    183\u001b[0m     )\n\u001b[1;32m    185\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m conn\n",
      "\u001b[0;31mNewConnectionError\u001b[0m: <urllib3.connection.HTTPConnection object at 0x7f1a8f306130>: Failed to establish a new connection: [Errno 111] Connection refused",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[0;31mMaxRetryError\u001b[0m                             Traceback (most recent call last)",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/requests/adapters.py:440\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m    439\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m chunked:\n\u001b[0;32m--> 440\u001b[0m     resp \u001b[38;5;241m=\u001b[39m \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43murlopen\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    441\u001b[0m \u001b[43m        \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    442\u001b[0m \u001b[43m        \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    443\u001b[0m \u001b[43m        \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    444\u001b[0m \u001b[43m        \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    445\u001b[0m \u001b[43m        \u001b[49m\u001b[43mredirect\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m    446\u001b[0m \u001b[43m        \u001b[49m\u001b[43massert_same_host\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m    447\u001b[0m \u001b[43m        \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m    448\u001b[0m \u001b[43m        \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m    449\u001b[0m \u001b[43m        \u001b[49m\u001b[43mretries\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmax_retries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    450\u001b[0m \u001b[43m        \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\n\u001b[1;32m    451\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    453\u001b[0m \u001b[38;5;66;03m# Send the request.\u001b[39;00m\n\u001b[1;32m    454\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/connectionpool.py:755\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001b[0m\n\u001b[1;32m    753\u001b[0m     e \u001b[38;5;241m=\u001b[39m ProtocolError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConnection aborted.\u001b[39m\u001b[38;5;124m\"\u001b[39m, e)\n\u001b[0;32m--> 755\u001b[0m retries \u001b[38;5;241m=\u001b[39m \u001b[43mretries\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mincrement\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    756\u001b[0m \u001b[43m    \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merror\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43me\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_pool\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_stacktrace\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msys\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexc_info\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[1;32m    757\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    758\u001b[0m retries\u001b[38;5;241m.\u001b[39msleep()\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/urllib3/util/retry.py:574\u001b[0m, in \u001b[0;36mRetry.increment\u001b[0;34m(self, method, url, response, error, _pool, _stacktrace)\u001b[0m\n\u001b[1;32m    573\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m new_retry\u001b[38;5;241m.\u001b[39mis_exhausted():\n\u001b[0;32m--> 574\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m MaxRetryError(_pool, url, error \u001b[38;5;129;01mor\u001b[39;00m ResponseError(cause))\n\u001b[1;32m    576\u001b[0m log\u001b[38;5;241m.\u001b[39mdebug(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIncremented Retry for (url=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m): \u001b[39m\u001b[38;5;132;01m%r\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, url, new_retry)\n",
      "\u001b[0;31mMaxRetryError\u001b[0m: HTTPConnectionPool(host='localhost', port=8501): Max retries exceeded with url: /v1/models/fashion_model:predict (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f1a8f306130>: Failed to establish a new connection: [Errno 111] Connection refused'))",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[0;31mConnectionError\u001b[0m                           Traceback (most recent call last)",
      "Input \u001b[0;32mIn [24]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mrequests\u001b[39;00m\n\u001b[1;32m      5\u001b[0m headers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent-type\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mapplication/json\u001b[39m\u001b[38;5;124m\"\u001b[39m}\n\u001b[0;32m----> 6\u001b[0m json_response \u001b[38;5;241m=\u001b[39m \u001b[43mrequests\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpost\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mhttp://localhost:8501/v1/models/fashion_model:predict\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m      7\u001b[0m predictions \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(json_response\u001b[38;5;241m.\u001b[39mtext)[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpredictions\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m      9\u001b[0m show(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThe model thought this was a \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m (class \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m), and it was actually a \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m (class \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m)\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mformat(\n\u001b[1;32m     10\u001b[0m   class_names[np\u001b[38;5;241m.\u001b[39margmax(predictions[\u001b[38;5;241m0\u001b[39m])], np\u001b[38;5;241m.\u001b[39margmax(predictions[\u001b[38;5;241m0\u001b[39m]), class_names[test_labels[\u001b[38;5;241m0\u001b[39m]], test_labels[\u001b[38;5;241m0\u001b[39m]))\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/requests/api.py:117\u001b[0m, in \u001b[0;36mpost\u001b[0;34m(url, data, json, **kwargs)\u001b[0m\n\u001b[1;32m    105\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpost\u001b[39m(url, data\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, json\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m    106\u001b[0m     \u001b[38;5;124mr\u001b[39m\u001b[38;5;124;03m\"\"\"Sends a POST request.\u001b[39;00m\n\u001b[1;32m    107\u001b[0m \n\u001b[1;32m    108\u001b[0m \u001b[38;5;124;03m    :param url: URL for the new :class:`Request` object.\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    114\u001b[0m \u001b[38;5;124;03m    :rtype: requests.Response\u001b[39;00m\n\u001b[1;32m    115\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[0;32m--> 117\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mpost\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mjson\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mjson\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/requests/api.py:61\u001b[0m, in \u001b[0;36mrequest\u001b[0;34m(method, url, **kwargs)\u001b[0m\n\u001b[1;32m     57\u001b[0m \u001b[38;5;66;03m# By using the 'with' statement we are sure the session is closed, thus we\u001b[39;00m\n\u001b[1;32m     58\u001b[0m \u001b[38;5;66;03m# avoid leaving sockets open which can trigger a ResourceWarning in some\u001b[39;00m\n\u001b[1;32m     59\u001b[0m \u001b[38;5;66;03m# cases, and look like a memory leak in others.\u001b[39;00m\n\u001b[1;32m     60\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m sessions\u001b[38;5;241m.\u001b[39mSession() \u001b[38;5;28;01mas\u001b[39;00m session:\n\u001b[0;32m---> 61\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43msession\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/requests/sessions.py:529\u001b[0m, in \u001b[0;36mSession.request\u001b[0;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001b[0m\n\u001b[1;32m    524\u001b[0m send_kwargs \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m    525\u001b[0m     \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtimeout\u001b[39m\u001b[38;5;124m'\u001b[39m: timeout,\n\u001b[1;32m    526\u001b[0m     \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mallow_redirects\u001b[39m\u001b[38;5;124m'\u001b[39m: allow_redirects,\n\u001b[1;32m    527\u001b[0m }\n\u001b[1;32m    528\u001b[0m send_kwargs\u001b[38;5;241m.\u001b[39mupdate(settings)\n\u001b[0;32m--> 529\u001b[0m resp \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprep\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43msend_kwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    531\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m resp\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/requests/sessions.py:645\u001b[0m, in \u001b[0;36mSession.send\u001b[0;34m(self, request, **kwargs)\u001b[0m\n\u001b[1;32m    642\u001b[0m start \u001b[38;5;241m=\u001b[39m preferred_clock()\n\u001b[1;32m    644\u001b[0m \u001b[38;5;66;03m# Send the request\u001b[39;00m\n\u001b[0;32m--> 645\u001b[0m r \u001b[38;5;241m=\u001b[39m \u001b[43madapter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    647\u001b[0m \u001b[38;5;66;03m# Total elapsed time of the request (approximately)\u001b[39;00m\n\u001b[1;32m    648\u001b[0m elapsed \u001b[38;5;241m=\u001b[39m preferred_clock() \u001b[38;5;241m-\u001b[39m start\n",
      "File \u001b[0;32m/usr/local/lib/python3.8/dist-packages/requests/adapters.py:519\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m    515\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e\u001b[38;5;241m.\u001b[39mreason, _SSLError):\n\u001b[1;32m    516\u001b[0m         \u001b[38;5;66;03m# This branch is for urllib3 v1.22 and later.\u001b[39;00m\n\u001b[1;32m    517\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m SSLError(e, request\u001b[38;5;241m=\u001b[39mrequest)\n\u001b[0;32m--> 519\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mConnectionError\u001b[39;00m(e, request\u001b[38;5;241m=\u001b[39mrequest)\n\u001b[1;32m    521\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m ClosedPoolError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m    522\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mConnectionError\u001b[39;00m(e, request\u001b[38;5;241m=\u001b[39mrequest)\n",
      "\u001b[0;31mConnectionError\u001b[0m: HTTPConnectionPool(host='localhost', port=8501): Max retries exceeded with url: /v1/models/fashion_model:predict (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f1a8f306130>: Failed to establish a new connection: [Errno 111] Connection refused'))"
     ]
    }
   ],
   "source": [
    "# docs_infra: no_execute\n",
    "!pip install -q requests\n",
    "\n",
    "import requests\n",
    "headers = {\"content-type\": \"application/json\"}\n",
    "json_response = requests.post('http://localhost:8501/v1/models/fashion_model:predict', data=data, headers=headers)\n",
    "predictions = json.loads(json_response.text)['predictions']\n",
    "\n",
    "show(0, 'The model thought this was a {} (class {}), and it was actually a {} (class {})'.format(\n",
    "  class_names[np.argmax(predictions[0])], np.argmax(predictions[0]), class_names[test_labels[0]], test_labels[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "YJH8LtM4XELp"
   },
   "source": [
    "#### A particular version of the servable\n",
    "\n",
    "Now let's specify a particular version of our servable.  Since we only have one, let's select version 1.  We'll also look at all three results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "zRftRxeR1tZx"
   },
   "outputs": [],
   "source": [
    "# docs_infra: no_execute\n",
    "headers = {\"content-type\": \"application/json\"}\n",
    "json_response = requests.post('http://localhost:8501/v1/models/fashion_model/versions/1:predict', data=data, headers=headers)\n",
    "predictions = json.loads(json_response.text)['predictions']\n",
    "\n",
    "for i in range(0,3):\n",
    "  show(i, 'The model thought this was a {} (class {}), and it was actually a {} (class {})'.format(\n",
    "    class_names[np.argmax(predictions[i])], np.argmax(predictions[i]), class_names[test_labels[i]], test_labels[i]))"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [],
   "name": "rest_simple.ipynb",
   "provenance": [],
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
